import React, { useEffect, useState, useCallback } from 'react';
import axios from 'axios';
import {
  Drawer,
  IconButton,
  List,
  ListItem,
  ListItemText,
  Typography,
  Box,
  Collapse,
  Chip,
  Button,
  CircularProgress,
  ButtonGroup,
  Tooltip,
  Tabs,
  Tab,
  TextField,
  InputAdornment
} from '@mui/material';
import {
  Menu as MenuIcon,
  ExpandLess,
  ExpandMore,
  Input as InputIcon,
  Output as OutputIcon,
  Add as AddIcon,
  Search as SearchIcon,
  Clear as ClearIcon
} from '@mui/icons-material';
import './SwaggerVisualizer.css';
import CustomApiManager from './CustomApiManager';

// 将搜索框组件移到组件外部，避免重复渲染
const SearchBar = ({ value, onChange, placeholder }) => (
  <Box sx={{ p: 2, borderBottom: '1px solid #eee' }}>
    <TextField
      fullWidth
      size="small"
      placeholder={placeholder}
      value={value}
      onChange={(e) => onChange(e.target.value)}
      InputProps={{
        startAdornment: (
          <InputAdornment position="start">
            <SearchIcon color="action" />
          </InputAdornment>
        ),
        endAdornment: value && (
          <InputAdornment position="end">
            <IconButton
              size="small"
              onClick={() => onChange('')}
              edge="end"
            >
              <ClearIcon />
            </IconButton>
          </InputAdornment>
        ),
        sx: { borderRadius: 2 }
      }}
    />
  </Box>
);

function SwaggerVisualizer({ onSelectSchema, xInputsCount = 0, resetCounter = false }) {
  const [swaggerData, setSwaggerData] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(false);
  const [drawerOpen, setDrawerOpen] = useState(false);
  const [expandedPath, setExpandedPath] = useState(null);
  const [searchTerm, setSearchTerm] = useState('');
  const [selectedMethod, setSelectedMethod] = useState('all');
  const [activeTab, setActiveTab] = useState('swagger');
  const [swaggerSearchTerm, setSwaggerSearchTerm] = useState('');

  // 支持多个 Swagger 地址
  const swaggerUrls = process.env.REACT_APP_SWAGGER_URLS 
    ? JSON.parse(process.env.REACT_APP_SWAGGER_URLS) 
    : [{
        name: 'Default API',
        url: process.env.REACT_APP_SWAGGER_URL || 'https://example.com/swagger.json'
      }];
  
  const [selectedSwaggerUrl, setSelectedSwaggerUrl] = useState(swaggerUrls[0]);

  const fetchSwaggerData = async (swaggerUrl) => {
    setLoading(true);
    try {
      // 使用 REACT_APP_API_BASE_URL 作为基础域名
      const baseUrl = process.env.REACT_APP_Swagger_BASE_URL;
      const fullUrl = `${baseUrl}${swaggerUrl}`;
      
      const response = await axios.get(fullUrl);
      const data = response.data;
      
      // 添加时间戳到缓存数据
      const cacheData = {
        timestamp: new Date().getTime(),
        data: data
      };
      
      setSwaggerData(data);
      setError(null);
      // 将数据存储到本地缓存
      localStorage.setItem(`swaggerData_${swaggerUrl}`, JSON.stringify(cacheData));
    } catch (err) {
      setError(`无法加载 Swagger 数据: ${err.message}`);
      console.error(err);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    const loadSwaggerData = () => {
      // 从缓存加载数据
      const cachedData = localStorage.getItem(`swaggerData_${selectedSwaggerUrl.url}`);
      if (cachedData) {
        const { timestamp, data } = JSON.parse(cachedData);
        const now = new Date().getTime();
        // 缓存时间超过1小时则重新获取
        if (now - timestamp > 3600000) {
          fetchSwaggerData(selectedSwaggerUrl.url);
        } else {
          setSwaggerData(data);
        }
      } else {
        fetchSwaggerData(selectedSwaggerUrl.url);
      }
    };

    loadSwaggerData();
  }, [selectedSwaggerUrl]);

  const handleRefresh = () => {
    fetchSwaggerData(selectedSwaggerUrl.url);
  };

  const handleSwaggerUrlChange = (event) => {
    const selected = swaggerUrls.find(url => url.name === event.target.value);
    setSelectedSwaggerUrl(selected);
  };

  const filterEndpoints = () => {
    if (!swaggerData?.paths) return [];
    
    return Object.entries(swaggerData.paths)
      .filter(([path]) => 
        path.toLowerCase().includes(searchTerm.toLowerCase())
      )
      .filter(([_, methods]) => 
        selectedMethod === 'all' || Object.keys(methods).includes(selectedMethod)
      );
  };

  const renderEndpointDetails = (path, methods) => {
    return Object.entries(methods).map(([method, details]) => (
      <div key={`${path}-${method}`} className="endpoint-method">
        <div className={`method-badge ${method}`}>
          {method.toUpperCase()}
        </div>
        <div className="endpoint-details">
          <h4>{details.summary || path}</h4>
          <p className="description">{details.description}</p>
          
          {details.parameters && details.parameters.length > 0 && (
            <div className="parameters">
              <h5>Parameters:</h5>
              <table>
                <thead>
                  <tr>
                    <th>Name</th>
                    <th>In</th>
                    <th>Type</th>
                    <th>Required</th>
                    <th>Description</th>
                  </tr>
                </thead>
                <tbody>
                  {details.parameters.map((param) => (
                    <tr key={param.name}>
                      <td>{param.name}</td>
                      <td>{param.in}</td>
                      <td>{param.type || (param.schema && param.schema.type)}</td>
                      <td>{param.required ? '✓' : '✗'}</td>
                      <td>{param.description}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          )}

          <div className="responses">
            <h5>Responses:</h5>
            {Object.entries(details.responses).map(([code, response]) => (
              <div key={code} className={`response-code code-${code[0]}xx`}>
                <span className="status-code">{code}</span>
                <span className="response-description">{response.description}</span>
              </div>
            ))}
          </div>
        </div>
      </div>
    ));
  };

  const handleMethodClick = (path, method, details) => {
    const methodData = {
      path,
      method: method.toUpperCase(),
      parameters: details.parameters || [],
      requestBody: details.requestBody,
      responses: details.responses
    };
    
    setExpandedPath(expandedPath === `${path}-${method}` ? null : `${path}-${method}`);
  };

  const getNextInputId = () => {
    return String.fromCharCode(65 + xInputsCount);
  };

  // 添加一个工具函数来生成默认值
  const getDefaultValueByType = (type) => {
    switch (type) {
      case 'integer':
      case 'number':
        return 0;
      case 'boolean':
        return false;
      case 'array':
        return [];
      case 'object':
        return {};
      default:
        return 'string';
    }
  };

  // 修改 resolveSchemaRef 函数
  const resolveSchemaRef = (schema, swaggerData) => {
    if (!schema) return null;

    // 处理 $ref 引用
    if (schema.$ref) {
      try {
        const refPath = schema.$ref.split('/');
        const schemaName = refPath[refPath.length - 1];
        
        let modelSchema;
        if (swaggerData.components?.schemas?.[schemaName]) {
          modelSchema = swaggerData.components.schemas[schemaName];
        } else if (swaggerData.definitions?.[schemaName]) {
          modelSchema = swaggerData.definitions[schemaName];
        }

        if (!modelSchema) {
          console.error(`Model not found: ${schemaName}`);
          return null;
        }

        // 检查是否是标准响应结构
        if (modelSchema.properties && modelSchema.properties.d) {
          // 只处理 d 属性
          const dProperty = modelSchema.properties.d;
          if (dProperty.$ref) {
            // 如果 d 属性是引用，递归解析
            return resolveSchemaRef(dProperty, swaggerData);
          } else if (dProperty.type === 'array' && dProperty.items) {
            // 如果 d 是数组类型
            const itemValue = dProperty.items.$ref ? 
              resolveSchemaRef(dProperty.items, swaggerData) : 
              getDefaultValueByType(dProperty.items.type);
            return [itemValue];
          } else if (dProperty.type === 'object' && dProperty.properties) {
            // 如果 d 是对象类型
            const result = {};
            Object.entries(dProperty.properties).forEach(([key, prop]) => {
              if (prop.$ref) {
                result[key] = resolveSchemaRef(prop, swaggerData);
              } else {
                result[key] = prop.example || getDefaultValueByType(prop.type);
              }
            });
            return result;
          } else {
            // 如果 d 是基本类型
            return dProperty.example || getDefaultValueByType(dProperty.type);
          }
        }

        // 如果不是标准响应结构，处理整个模型
        const result = {};
        if (modelSchema.properties) {
          Object.entries(modelSchema.properties).forEach(([key, prop]) => {
            if (prop.$ref) {
              result[key] = resolveSchemaRef(prop, swaggerData);
            } else {
              result[key] = prop.example || getDefaultValueByType(prop.type);
            }
          });
        }
        return result;

      } catch (error) {
        console.error('Error resolving schema reference:', error);
        return null;
      }
    }

    // 如果是直接的对象定义
    if (schema.type === 'object' && schema.properties) {
      // 检查是否是标准响应结构
      if (schema.properties.d) {
        // 只处理 d 属性
        const dProperty = schema.properties.d;
        if (dProperty.$ref) {
          return resolveSchemaRef(dProperty, swaggerData);
        } else if (dProperty.type === 'array' && dProperty.items) {
          const itemValue = dProperty.items.$ref ? 
            resolveSchemaRef(dProperty.items, swaggerData) : 
            getDefaultValueByType(dProperty.items.type);
          return [itemValue];
        } else if (dProperty.type === 'object' && dProperty.properties) {
          const result = {};
          Object.entries(dProperty.properties).forEach(([key, prop]) => {
            if (prop.$ref) {
              result[key] = resolveSchemaRef(prop, swaggerData);
            } else {
              result[key] = prop.example || getDefaultValueByType(prop.type);
            }
          });
          return result;
        } else {
          return dProperty.example || getDefaultValueByType(dProperty.type);
        }
      }

      // 如果不是标准响应结构，处理整个对象
      const result = {};
      Object.entries(schema.properties).forEach(([key, prop]) => {
        if (prop.$ref) {
          result[key] = resolveSchemaRef(prop, swaggerData);
        } else {
          result[key] = prop.example || getDefaultValueByType(prop.type);
        }
      });
      return result;
    }

    // 如果是数组类型
    if (schema.type === 'array' && schema.items) {
      const itemValue = schema.items.$ref ? 
        resolveSchemaRef(schema.items, swaggerData) : 
        getDefaultValueByType(schema.items.type);
      return [itemValue];
    }

    // 返回基本类型的默认值
    return getDefaultValueByType(schema.type);
  };

  // 修改 handleSchemaSelect 函数
  const handleSchemaSelect = (schema, type) => {
    try {
      // 直接使用解析后的值作为数据
      const resolvedData = resolveSchemaRef(schema, swaggerData);
      
      if (!resolvedData) {
        console.error('Failed to resolve schema');
        return;
      }

      if (type === 'x') {
        const id = getNextInputId();
        onSelectSchema({
          type: 'x',
          id,
          data: resolvedData
        });
      } else {
        onSelectSchema({
          type: 'y',
          data: resolvedData
        });
      }
    } catch (error) {
      console.error('Error processing schema:', error);
    }
  };

  const renderMethodItem = (path, method, details) => {
    const isExpanded = expandedPath === `${path}-${method}`;
    
    // 检查请求体和响应体的 content type
    const hasRequestBody = details.requestBody?.content?.['application/json']?.schema;
    const hasResponseBody = details.responses?.['200']?.content?.['application/json']?.schema;
    
    return (
      <Box key={`${path}-${method}`} className="method-item">
        <ListItem 
          button 
          onClick={() => handleMethodClick(path, method, details)}
          className={`method-${method.toLowerCase()}`}
        >
          <Chip 
            label={method.toUpperCase()} 
            size="small" 
            className={`method-chip ${method.toLowerCase()}`}
          />
          <ListItemText 
            primary={path}
            secondary={details.summary} 
            className="method-text"
          />
          {isExpanded ? <ExpandLess /> : <ExpandMore />}
        </ListItem>
        
        <Collapse in={isExpanded} timeout="auto" unmountOnExit>
          <Box className="method-details">
            {/* 请求参数按钮组 */}
            {details.parameters && details.parameters.length > 0 && (
              <ButtonGroup variant="contained" className="schema-button-group">
                <Tooltip title="添加为新的X输入">
                  <Button
                    startIcon={<AddIcon />}
                    onClick={() => handleSchemaSelect(details.parameters, 'x')}
                    className="schema-button"
                  >
                    添加为输入X ({getNextInputId()})
                  </Button>
                </Tooltip>
                <Tooltip title="设置为Y输出">
                  <Button
                    startIcon={<OutputIcon />}
                    onClick={() => handleSchemaSelect(details.parameters, 'y')}
                    className="schema-button"
                  >
                    设为输出Y
                  </Button>
                </Tooltip>
              </ButtonGroup>
            )}
            
            {/* 请求体按钮组 */}
            {hasRequestBody && (
              <ButtonGroup variant="contained" className="schema-button-group">
                <Tooltip title="添加为新的X输入">
                  <Button
                    startIcon={<AddIcon />}
                    onClick={() => handleSchemaSelect(details.requestBody.content['application/json'].schema, 'x')}
                    className="schema-button"
                  >
                    添加入参为输入X ({getNextInputId()})
                  </Button>
                </Tooltip>
                <Tooltip title="设置为Y输出">
                  <Button
                    startIcon={<OutputIcon />}
                    onClick={() => handleSchemaSelect(details.requestBody.content['application/json'].schema, 'y')}
                    className="schema-button"
                  >
                    添加入参为输入Y
                  </Button>
                </Tooltip>
              </ButtonGroup>
            )}
            
            {/* 响应体按钮组 */}
            {hasResponseBody && (
              <ButtonGroup variant="contained" className="schema-button-group">
                <Tooltip title="添加新的X输入">
                  <Button
                    startIcon={<AddIcon />}
                    onClick={() => handleSchemaSelect(details.responses['200'].content['application/json'].schema, 'x')}
                    className="schema-button"
                  >
                    添加出参输入X ({getNextInputId()})
                  </Button>
                </Tooltip>
                <Tooltip title="设置为Y输出">
                  <Button
                    startIcon={<OutputIcon />}
                    onClick={() => handleSchemaSelect(details.responses['200'].content['application/json'].schema, 'y')}
                    className="schema-button"
                  >
                    添加出参为输入Y
                  </Button>
                </Tooltip>
              </ButtonGroup>
            )}
          </Box>
        </Collapse>
      </Box>
    );
  };

  // 添加对 resetCounter 的监听
  useEffect(() => {
    if (resetCounter) {
      // 重置内部状态（如果有的话）
      setSelectedMethod('all');
      setSearchTerm('');
      setExpandedPath(null);
    }
  }, [resetCounter]);

  // 使用 useCallback 优化搜索处理函数
  const handleSearchChange = useCallback((value) => {
    setSwaggerSearchTerm(value);
  }, []);

  return (
    <>
      <IconButton
        onClick={() => setDrawerOpen(true)}
        className="drawer-toggle"
        sx={{ position: 'fixed', right: 16, top: 16 }}
      >
        <MenuIcon />
      </IconButton>

      <Drawer
        anchor="right"
        open={drawerOpen}
        onClose={() => setDrawerOpen(false)}
        className="swagger-drawer"
      >
        <Box className="drawer-content" sx={{ width: 350 }}>
          <Tabs
            value={activeTab}
            onChange={(e, newValue) => setActiveTab(newValue)}
            sx={{ borderBottom: 1, borderColor: 'divider' }}
          >
            <Tab label="Swagger API" value="swagger" />
            <Tab label="自定义接口" value="custom" />
          </Tabs>

          {activeTab === 'swagger' ? (
            <Box>
              <Box className="drawer-header">
                <Typography variant="h6">API 文档</Typography>
                <select 
                  value={selectedSwaggerUrl.name}
                  onChange={handleSwaggerUrlChange}
                  className="url-selector"
                >
                  {swaggerUrls.map(url => (
                    <option key={url.name} value={url.name}>
                      {url.name}
                    </option>
                  ))}
                </select>
                <Button 
                  onClick={handleRefresh}
                  disabled={loading}
                  className="refresh-button"
                >
                  {loading ? 'Loading...' : 'Refresh'}
                </Button>
              </Box>

              <SearchBar 
                value={swaggerSearchTerm}
                onChange={handleSearchChange}
                placeholder="搜索接口描述..."
              />

              {error && <div className="error-message">{error}</div>}

              <List className="endpoints-list">
                {swaggerData && Object.entries(swaggerData.paths)
                  .filter(([path, methods]) => {
                    const searchText = swaggerSearchTerm.toLowerCase();
                    return Object.values(methods).some(method => 
                      method.summary?.toLowerCase().includes(searchText) ||
                      method.description?.toLowerCase().includes(searchText) ||
                      path.toLowerCase().includes(searchText)
                    );
                  })
                  .map(([path, methods]) => (
                    Object.entries(methods).map(([method, details]) => 
                      renderMethodItem(path, method, details)
                    )
                  ))}
              </List>
            </Box>
          ) : (
            <CustomApiManager onSelectSchema={onSelectSchema} />
          )}
        </Box>
      </Drawer>
    </>
  );
}

export default SwaggerVisualizer; 